package lu;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Random;

/**
 * 显示画布，就是一个容器
 */
public class SnakePanel extends JPanel implements KeyListener, ActionListener {
    //加载所有的图片
    ImageIcon up = new ImageIcon("src\\Image\\up.png");
    ImageIcon down = new ImageIcon("src\\Image\\down.png");
    ImageIcon right = new ImageIcon("src\\Image\\right.png");
    ImageIcon left = new ImageIcon("src\\Image\\left.png");
    ImageIcon food = new ImageIcon("src\\Image\\food.jpg");
    ImageIcon body = new ImageIcon("src\\Image\\body.png");
    ImageIcon title = new ImageIcon("src\\Image\\title.png");

    //蛇的数据结构的设计
    int[] snakex = new int[750];
    int[] snakey = new int[750];
    int len = 3;
    String direction = "L";//right右

    //食物的数据
    Random x = new Random();//产生0-1之间的随机小数，不包括两个端点
    int foodx = x.nextInt(34)*25+25;  //通过x.nextInt(34)可以生成0-34之间的随即整数，*25 是以为每个格子有25个像素，+25是为了加上边缘空白的像素
    int foody = x.nextInt(24)*25+75;  //同上


    //定义游戏的开始和暂停的状态
    boolean isStarted=false;

    //定义游戏是否失败
    boolean isFailed=false;

    //定时器来触发蛇移动
    Timer timer = new Timer(150,this::actionPerformed);//每隔150毫秒，就执行一次Actionlistener监听器内的内容，即通过动作监听器来控制蛇的移动

    //构造函数
    public SnakePanel(){
        this.setFocusable(true);//设置画布可以获取焦点
        initSnake();//放置静态蛇
        this.addKeyListener(this);//添加键盘监听接口
        timer.start();//定时触发器开始工作
    }

    //初始化蛇
    public void initSnake(){

        //初始状态时游戏未开始，游戏也未失败
        isStarted = false;
        isFailed = false;

        //开始时基本数据配置

        direction="R";
        snakex[0] = 100;
        snakey[0] = 100;
        snakex[1] = 75;
        snakey[1] = 100;
        snakex[2] = 50;
        snakey[2] = 100;
        for(int i=3;i<len;i++){//将之前游戏残留的数据清楚，不然会对后面产生一点影响
            snakex[i]=0;
            snakey[i]=0;
        }
        len = 3;


    }

    //通过 Graphics类 画笔显示界面
    public  void paint(Graphics g){
        //设置画布的背景颜色
        this.setBackground(Color.black);
        g.fillRect(25,75,850,600);
        //设置标题
        title.paintIcon(this,g,25,11);

        //画蛇头 判断蛇头的方向
        if(direction.equals("R")){
            right.paintIcon(this,g,snakex[0],snakey[0]);
        }else if(direction.equals("L")){
            left.paintIcon(this,g,snakex[0],snakey[0]);
        }else if(direction.equals("U")){
            up.paintIcon(this,g,snakex[0],snakey[0]);
        }else if(direction.equals("D")){
            down.paintIcon(this,g,snakex[0],snakey[0]);
        }
        //画蛇身
        for(int i = 1;i < len;i++){
            body.paintIcon(this,g,snakex[i],snakey[i]);//只要len数据增加了，蛇的身体就会边长
        }

        //画开始提示语
        if(!isStarted){
            g.setColor(Color.white);//画笔颜色
            g.setFont(new Font("arial",Font.BOLD,30));//画出的字体，粗细，大小
            g.drawString("Press Space to Start/Pause",300,300);//画出的提示语内容和内容展示的相对位置
        }

        //画游戏失败提示语
        if(isFailed){
            g.setColor(Color.white);//画笔颜色
            g.setFont(new Font("arial",Font.BOLD,30));//画出的字体，粗细，大小
            g.drawString("Game Over ! Press Space to Start",300,300);//画出的提示语内容和内容展示的相对位置
        }

        //画食物
        food.paintIcon(this,g,foodx,foody);

        //画分数和蛇的长度
        g.setColor(Color.white);//画笔颜色
        g.setFont(new Font("arial",Font.PLAIN,15));//画出的字体，粗细，大小
        g.drawString("Score:"+" "+(len-3)*10,730,25);//画出的提示语内容和内容展示的相对位置
        g.drawString("Long :"+" "+len,730,45);//画出的提示语内容和内容展示的相对位置
    }

    @Override
    public void keyTyped(KeyEvent e) {

    }

    @Override
    //当按下空格时的暂停与开始功能  监听空格  监听方向键
    public void keyPressed(KeyEvent e) {
        int keyCode = e.getKeyCode();
        //判断获取的是空格
        if(keyCode == KeyEvent.VK_SPACE){
            if(isFailed){
                initSnake();
            }else{
                isStarted = !isStarted;//取相反的值，就可以做到在开始的状态变为暂停，暂停变为开始
            }
            repaint();//重画
        }

        if(isStarted && !isFailed){
            if(keyCode== KeyEvent.VK_UP && !direction.equals("D")){//监听键盘的向上键  !direction.equals("D")让蛇不能直接改变为完全相反的方向
            direction="U";
            }

            if(keyCode== KeyEvent.VK_DOWN && !direction.equals("U")){//监听键盘的向下键
            direction="D";
            }

            if(keyCode== KeyEvent.VK_RIGHT && !direction.equals("L")){//监听键盘的右键
            direction="R";
            }

            if(keyCode== KeyEvent.VK_LEFT && !direction.equals("R")){//监听键盘的左键
            direction="L";
            }
        }

    }

    @Override
    public void keyReleased(KeyEvent e) {

    }

    /**
     * 1.重新定个闹钟（触发器timer）
     * 2.蛇移动，头和身体的坐标变化
     * 3.重画
     * @param e
     */
    @Override
    public void actionPerformed(ActionEvent e) {
        //timer.start();
        timer.setDelay(150-len*2);//随着身体长度的增加，增加移速

        if (isStarted && !isFailed){
            //移动身体，蛇最后一个部分的坐标应该变成该部分前面的部分的坐标，从尾部开始变化，头部的变化根据键盘的而控制来决定
            for(int i=len-1;i>0;i--){
                snakex[i] = snakex[i-1];
                snakey[i] = snakey[i-1];
            }
            //移动头部
            if(direction.equals("R")){
                //横坐标+25
                snakex[0] = snakex[0] + 25;
                if(snakex[0]>850) {//穿墙   下同
                   //snakex[0]=25;
                    isFailed=true;//撞墙死亡结束游戏， 下同
                    snakex[0] = snakex[0] - 25;//死亡时，蛇头不能显示在游戏界面外，不然会留下残图，下同
                }
            }else if(direction.equals("L")){
                //横坐标-25
                snakex[0] = snakex[0] - 25;
                if(snakex[0]<25){
                    //snakex[0]=850;
                    isFailed=true;
                    snakex[0] = snakex[0] + 25;
                }
            }else if(direction.equals("U")){
                //纵坐标-25
                snakey[0] = snakey[0] - 25;
                if(snakey[0]<75){
                    //snakey[0]=650;
                    isFailed=true;
                    snakey[0] = snakey[0] + 25;
                }
            }else if(direction.equals("D")){
                //纵坐标+25
                snakey[0] = snakey[0] + 25;
                if(snakey[0]>650){
                    //snakey[0]=75;
                    isFailed=true;
                    snakey[0] = snakey[0] - 25;
                }
            }

            //吃食物  当蛇头和食物的位置相等时，说明吃掉了食物,食物就要换一个位置产生
            if (snakex[0] == foodx && snakey[0] == foody){
                //蛇身边长
                len = len + 1;

                //产生新的食物
                //Random x = new Random();//产生0-1之间的随机小数，不包括两个端点
                foodx = x.nextInt(34)*25+25;  //通过x.nextInt(34)可以生成0-34之间的随即整数，*25 是以为每个格子有25个像素，+25是为了加上边缘空白的像素
                foody = x.nextInt(24)*25+75;  //同上
            }

            //判断蛇撞上自己而死亡，即蛇头和身体的坐标重合时结束游戏
            for (int i=1;i<=len;i++){
                if(snakex[0] == snakex[i] && snakey[0] == snakey[i]){
                    isFailed=true;
                }
            }


        }
        repaint();//重画
    }
}
